from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
import secrets
import hashlib

from app.config import settings

# Password hashing context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class SecurityUtils:
    """安全工具类"""
    
    @staticmethod
    def verify_password(plain_password: str, hashed_password: str) -> bool:
        """验证密码"""
        return pwd_context.verify(plain_password, hashed_password)
    
    @staticmethod
    def get_password_hash(password: str) -> str:
        """生成密码哈希"""
        return pwd_context.hash(password)
    
    @staticmethod
    def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
        """创建访问令牌"""
        to_encode = data.copy()
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
        
        to_encode.update({"exp": expire, "type": "access"})
        encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm="HS256")
        return encoded_jwt
    
    @staticmethod
    def create_refresh_token(data: Dict[str, Any]) -> str:
        """创建刷新令牌"""
        to_encode = data.copy()
        expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
        to_encode.update({"exp": expire, "type": "refresh"})
        encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm="HS256")
        return encoded_jwt
    
    @staticmethod
    def verify_token(token: str, token_type: str = "access") -> Optional[Dict[str, Any]]:
        """验证令牌"""
        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            if payload.get("type") != token_type:
                return None
            return payload
        except JWTError:
            return None
    
    @staticmethod
    def generate_api_key() -> str:
        """生成API密钥"""
        return secrets.token_urlsafe(32)
    
    @staticmethod
    def generate_secure_token(length: int = 32) -> str:
        """生成安全令牌"""
        return secrets.token_urlsafe(length)
    
    @staticmethod
    def hash_string(text: str, salt: Optional[str] = None) -> str:
        """生成字符串哈希"""
        if salt:
            text = text + salt
        return hashlib.sha256(text.encode()).hexdigest()
    
    @staticmethod
    def validate_password_strength(password: str) -> Dict[str, Any]:
        """验证密码强度"""
        result = {
            "is_valid": True,
            "score": 0,
            "issues": []
        }
        
        # 长度检查
        if len(password) < 8:
            result["issues"].append("密码长度至少8位")
            result["is_valid"] = False
        else:
            result["score"] += 1
        
        # 包含大写字母
        if any(c.isupper() for c in password):
            result["score"] += 1
        else:
            result["issues"].append("密码应包含大写字母")
        
        # 包含小写字母
        if any(c.islower() for c in password):
            result["score"] += 1
        else:
            result["issues"].append("密码应包含小写字母")
        
        # 包含数字
        if any(c.isdigit() for c in password):
            result["score"] += 1
        else:
            result["issues"].append("密码应包含数字")
        
        # 包含特殊字符
        special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
        if any(c in special_chars for c in password):
            result["score"] += 1
        else:
            result["issues"].append("密码应包含特殊字符")
        
        # 评分标准
        if result["score"] < 3:
            result["strength"] = "weak"
        elif result["score"] < 4:
            result["strength"] = "medium"
        else:
            result["strength"] = "strong"
        
        return result

class RateLimiter:
    """简单的速率限制器"""
    
    def __init__(self):
        self.requests = {}  # {key: [timestamps]}
        self.limits = {
            "login": {"count": 5, "window": 300},  # 5次/5分钟
            "api": {"count": 100, "window": 60},   # 100次/分钟
            "websocket": {"count": 10, "window": 60}  # 10次/分钟
        }
    
    def is_allowed(self, key: str, limit_type: str = "api") -> bool:
        """检查是否允许请求"""
        now = datetime.utcnow().timestamp()
        limit_config = self.limits.get(limit_type, self.limits["api"])
        
        if key not in self.requests:
            self.requests[key] = []
        
        # 清理过期的请求记录
        window_start = now - limit_config["window"]
        self.requests[key] = [ts for ts in self.requests[key] if ts > window_start]
        
        # 检查是否超过限制
        if len(self.requests[key]) >= limit_config["count"]:
            return False
        
        # 记录当前请求
        self.requests[key].append(now)
        return True
    
    def get_remaining(self, key: str, limit_type: str = "api") -> int:
        """获取剩余请求次数"""
        now = datetime.utcnow().timestamp()
        limit_config = self.limits.get(limit_type, self.limits["api"])
        
        if key not in self.requests:
            return limit_config["count"]
        
        # 清理过期的请求记录
        window_start = now - limit_config["window"]
        self.requests[key] = [ts for ts in self.requests[key] if ts > window_start]
        
        return max(0, limit_config["count"] - len(self.requests[key]))

# 全局速率限制器实例
rate_limiter = RateLimiter()

class PermissionChecker:
    """权限检查器"""
    
    # 权限定义
    PERMISSIONS = {
        "admin": [
            "task:create", "task:read", "task:update", "task:delete",
            "task:start", "task:stop", "task:restart",
            "user:create", "user:read", "user:update", "user:delete",
            "system:read", "system:update", "system:manage",
            "logs:read", "metrics:read"
        ],
        "user": [
            "task:create", "task:read", "task:update", "task:delete",
            "task:start", "task:stop", "task:restart",
            "logs:read", "metrics:read"
        ],
        "viewer": [
            "task:read", "logs:read", "metrics:read"
        ]
    }
    
    @classmethod
    def has_permission(cls, user_role: str, permission: str) -> bool:
        """检查用户是否有指定权限"""
        user_permissions = cls.PERMISSIONS.get(user_role, [])
        return permission in user_permissions
    
    @classmethod
    def get_user_permissions(cls, user_role: str) -> list:
        """获取用户的所有权限"""
        return cls.PERMISSIONS.get(user_role, [])
    
    @classmethod
    def can_access_task(cls, user_role: str, user_id: str, task_user_id: str) -> bool:
        """检查用户是否可以访问指定任务"""
        # 管理员可以访问所有任务
        if user_role == "admin":
            return True
        
        # 普通用户只能访问自己的任务
        return user_id == task_user_id

# 数据脱敏工具
class DataMasker:
    """数据脱敏工具"""
    
    @staticmethod
    def mask_email(email: str) -> str:
        """脱敏邮箱地址"""
        if "@" not in email:
            return email
        
        local, domain = email.split("@", 1)
        if len(local) <= 2:
            masked_local = "*" * len(local)
        else:
            masked_local = local[0] + "*" * (len(local) - 2) + local[-1]
        
        return f"{masked_local}@{domain}"
    
    @staticmethod
    def mask_phone(phone: str) -> str:
        """脱敏手机号"""
        if len(phone) <= 4:
            return "*" * len(phone)
        
        return phone[:3] + "*" * (len(phone) - 6) + phone[-3:]
    
    @staticmethod
    def mask_api_key(api_key: str) -> str:
        """脱敏API密钥"""
        if len(api_key) <= 8:
            return "*" * len(api_key)
        
        return api_key[:4] + "*" * (len(api_key) - 8) + api_key[-4:]
    
    @staticmethod
    def mask_sensitive_data(data: dict, fields: list = None) -> dict:
        """脱敏敏感数据"""
        if fields is None:
            fields = ["password", "token", "api_key", "secret"]
        
        masked_data = data.copy()
        for field in fields:
            if field in masked_data:
                if field in ["password", "token", "secret"]:
                    masked_data[field] = "***"
                elif field == "api_key":
                    masked_data[field] = DataMasker.mask_api_key(str(masked_data[field]))
                elif field == "email":
                    masked_data[field] = DataMasker.mask_email(str(masked_data[field]))
                elif field == "phone":
                    masked_data[field] = DataMasker.mask_phone(str(masked_data[field]))
        
        return masked_data
